home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
ms_sh21s.zip
/
SH210
/
SRC
/
SH2.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-14
|
30KB
|
1,367 lines
/* MS-DOS SHELL - Parser
*
* MS-DOS SHELL - Copyright (c) 1990,1,2 Data Logic Limited and Charles Forsyth
*
* This code is based on (in part) the shell program written by Charles
* Forsyth and is subject to the following copyright restrictions:
*
* 1. Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in the
* source form and the copyright notice in file sh6.c is displayed
* on entry to the program.
*
* 2. The sources (or parts thereof) or objects generated from the sources
* (or parts of sources) cannot be sold under any circumstances.
*
* $Header: /usr/users/istewart/src/shell/sh2.1/RCS/sh2.c,v 2.3 1992/11/06 10:03:44 istewart Exp $
*
* $Log: sh2.c,v $
* Revision 2.3 1992/11/06 10:03:44 istewart
* 214 Beta test updates
*
* Revision 2.3 1992/11/06 10:03:44 istewart
* 214 Beta test updates
*
* Revision 2.2 1992/09/03 18:54:45 istewart
* Beta 213 Updates
*
* Revision 2.1 1992/07/10 10:52:48 istewart
* 211 Beta updates
*
* Revision 2.0 1992/04/13 17:39:09 Ian_Stewartson
* MS-Shell 2.0 Baseline release
*
*/
#include <sys/types.h>
#include <stdio.h>
#include <stddef.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#ifdef OS2
#define INCL_DOSSESMGR
#include <os2.h>
#endif
#include "sh.h"
/*
* shell: syntax (C version)
*/
#define PARSE_WORD 256
#define PARSE_LOGICAL_AND 257
#define PARSE_LOGICAL_OR 258
#define PARSE_BREAK 259
#define PARSE_IF 260
#define PARSE_THEN 261
#define PARSE_ELSE 262
#define PARSE_ELIF 263
#define PARSE_FI 264
#define PARSE_CASE 265
#define PARSE_ESAC 266
#define PARSE_FOR 267
#define PARSE_WHILE 268
#define PARSE_UNTIL 269
#define PARSE_DO 270
#define PARSE_DONE 271
#define PARSE_IN 272
#define PARSE_SELECT 273
#define PARSE_FUNCTION 274
#define PARSE_EXPRESSION 275
#define PARSE_TEST 276
#define YYERRCODE 300
/* Static data */
static bool AtStartOfList;
static int PeekSymbol; /* Look ahead symbol */
static bool AllowFunctions; /* Allow functions */
static bool InAlias; /* In an alias already */
static bool AliasContinuationAllowed;
static bool ParseErrorDectected; /* Parse error occured */
static int CurrentIOUnit = IODEFAULT;
static union {
char *String;
int Integer;
} CurrentParseObject;
static char *SyntaxErrorMessage = "syntax error";
static char *MissingEndMessage = "no closing x";
static char *UnexpectCMessage = "unexpected closing x";
static bool near ProcessWordObject (C_Op **, bool);
static C_Op * near ScanPipeSyntax (bool);
static C_Op * near ScanAndOrSyntax (void);
static C_Op * near CommandList (bool);
static bool near SynchroniseIOList (bool);
static void near CheckNextSymbolIS (int, bool);
static C_Op * near ScanSimpleCommand (void);
static C_Op * near ScanNestedCommand (int, int);
static C_Op * near GetNextCommand (bool);
static C_Op * near GetDoDoneCommandList (bool);
static C_Op * near ThenPartList (void);
static C_Op * near ElsePartList (void);
static C_Op * near CaseList (void);
static C_Op * near CaseListEntries (void);
static char ** near GetCasePatterns (void);
static char ** near GetINWordList (void);
static C_Op * near GenerateListNode (C_Op *, C_Op *);
static C_Op * near InitialiseTreeNode (int, C_Op *, C_Op *, char **);
static char ** near CopyWordList (void);
static IO_Actions * near AddIOAction (int, int, char *);
static void near ParseError (char *);
static int near GetNextSymbol (bool);
static int near CheckForDoubleCharacterCommands (int);
static void near GetCurrentIOAction (int);
static char * near CreateTreeNode (size_t);
static int Alias_GetNextCharacter (IO_State *);
static int near MC_Error (int, int, char *);
static C_Op * near ParseExpression (int, char *);
/*
* Parse - main function
*/
C_Op *BuildParseTree (void)
{
C_Op *outtree;
AtStartOfList = TRUE;
PeekSymbol = 0;
ParseErrorDectected = FALSE;
LastUserPrompt = PS1;
/* Initialise alias information */
InAlias = FALSE;
AliasContinuationAllowed = FALSE;
/* Build the tree */
outtree = CommandList (TRUE);
CheckNextSymbolIS (CHAR_NEW_LINE, FALSE);
return ParseErrorDectected ? (C_Op *)NULL : outtree;
}
static C_Op * near ScanPipeSyntax (bool IgnoreNewLines)
{
register C_Op *t, *p;
register int c;
if ((t = GetNextCommand (IgnoreNewLines)) != (C_Op *)NULL)
{
AllowFunctions = FALSE;
while ((c = GetNextSymbol (FALSE)) == '|')
{
if ((p = GetNextCommand (TRUE)) == (C_Op *)NULL)
ParseError (SyntaxErrorMessage);
/* shell statement */
if ((t->type != TPAREN) && (t->type != TCOM))
t = InitialiseTreeNode (TPAREN, t, NOBLOCK, NOWORDS);
t = InitialiseTreeNode (TPIPE, t, p, NOWORDS);
}
PeekSymbol = c;
}
return t;
}
static C_Op * near ScanAndOrSyntax (void)
{
register C_Op *t, *p;
register int c;
if ((t = ScanPipeSyntax (FALSE)) != (C_Op *)NULL)
{
AllowFunctions = FALSE;
while (((c = GetNextSymbol (FALSE)) == PARSE_LOGICAL_AND) ||
(c == PARSE_LOGICAL_OR))
{
if ((p = ScanPipeSyntax (TRUE)) == (C_Op *)NULL)
ParseError (SyntaxErrorMessage);
t = InitialiseTreeNode ((c == PARSE_LOGICAL_AND) ? TAND : TOR,
t, p, NOWORDS);
}
PeekSymbol = c;
}
return t;
}
static C_Op * near CommandList (bool allow)
{
register C_Op *t, *p;
register int c;
/* Functions are only allowed at the start of a line */
AllowFunctions = allow;
if ((t = ScanAndOrSyntax ()) != (C_Op *)NULL)
{
AllowFunctions = FALSE;
if ((PeekSymbol = GetNextSymbol (FALSE)) == '&')
t = InitialiseTreeNode (TASYNC, t, NOBLOCK, NOWORDS);
while (((c = GetNextSymbol (FALSE)) == ';') || (c == '&') ||
(AllowMultipleLines && (c == CHAR_NEW_LINE)))
{
if ((p = ScanAndOrSyntax ()) == (C_Op *)NULL)
return t;
if ((PeekSymbol = GetNextSymbol (FALSE)) == '&')
p = InitialiseTreeNode (TASYNC, p, NOBLOCK, NOWORDS);
t = GenerateListNode (t, p);
}
PeekSymbol = c;
}
return t;
}
static bool near SynchroniseIOList (bool IgnoreNewLines)
{
register IO_Actions *iop;
register int i;
register int c;
if (((c = GetNextSymbol (IgnoreNewLines)) != '<') && (c != '>'))
{
PeekSymbol = c;
return FALSE;
}
i = CurrentParseObject.Integer;
CheckNextSymbolIS (PARSE_WORD, FALSE);
iop = AddIOAction (CurrentIOUnit, i, CurrentParseObject.String);
CurrentIOUnit = IODEFAULT;
if (i & IOHERE)
SaveHereFileInfo (CurrentParseObject.String, iop);
return TRUE;
}
/*
* Check the next symbol
*/
static void near CheckNextSymbolIS (int c, bool IgnoreNewLines)
{
if ((PeekSymbol = GetNextSymbol (IgnoreNewLines)) != c)
ParseError (SyntaxErrorMessage);
PeekSymbol = 0;
}
static C_Op * near ScanSimpleCommand (void)
{
C_Op *t = (C_Op *)NULL;
bool FoundAlias;
while (1)
{
FoundAlias = InAlias;
switch (PeekSymbol = GetNextSymbol (FALSE))
{
case '<':
case '>':
SynchroniseIOList (FALSE);
break;
/* Ok - we've found a word. If it is the first word - check for an alias */
case PARSE_WORD:
if (!ProcessWordObject (&t, FoundAlias))
continue;
break;
/* Check for function - name () { word; } */
case CHAR_OPEN_PARATHENSIS:
if ((t != (C_Op *)NULL) && AllowFunctions &&
(WordListBlock != (Word_B *)NULL) &&
(WordListBlock->w_nword == 1))
{
/* Check the format */
PeekSymbol = 0;
CheckNextSymbolIS (CHAR_CLOSE_PARATHENSIS, FALSE);
CheckNextSymbolIS (CHAR_OPEN_BRACES, FALSE);
/* Save the function name */
t->str = WordListBlock->w_words[0];
ReleaseMemoryCell ((void *)WordListBlock);
WordListBlock = (Word_B *)NULL;
t->type = TFUNC;
/* Get the function commands */
t->left = ScanNestedCommand (TBRACE, CHAR_CLOSE_BRACES);
AllowFunctions = FALSE;
CheckNextSymbolIS (CHAR_NEW_LINE, FALSE);
PeekSymbol = CHAR_NEW_LINE;
}
default:
return t;
}
}
}
/*
* Handle Nested thingys - ( and {
*/
static C_Op * near ScanNestedCommand (int type, int mark)
{
register C_Op *t;
AllowMultipleLines++;
t = CommandList (FALSE);
CheckNextSymbolIS (mark, FALSE);
AllowMultipleLines--;
return InitialiseTreeNode (type, t, NOBLOCK, NOWORDS);
}
/*
* Get the Next command
*/
static C_Op * near GetNextCommand (bool IgnoreNewLines)
{
register C_Op *t;
Word_B *iosave = IOActionBlock;
register int c;
IOActionBlock = (Word_B *)NULL;
if (AllowMultipleLines)
IgnoreNewLines = TRUE;
while (SynchroniseIOList (IgnoreNewLines))
IgnoreNewLines = FALSE;
switch (c = GetNextSymbol (IgnoreNewLines))
{
default:
PeekSymbol = c;
if ((t = ScanSimpleCommand ()) == (C_Op *)NULL)
{
if (IOActionBlock == (Word_B *)NULL)
return (C_Op *)NULL;
(t = (C_Op *)CreateTreeNode (sizeof (C_Op)))->type = TCOM;
}
break;
case PARSE_EXPRESSION:
AllowMultipleLines++;
t = ParseExpression (SWT_LET, "let");
AllowMultipleLines--;
break;
case PARSE_TEST:
AllowMultipleLines++;
t = ParseExpression (SWT_CONDITIONAL, "[[");
WordListBlock = AddWordToBlock (StringCopy ("]]"), WordListBlock);
AllowMultipleLines--;
break;
case CHAR_OPEN_PARATHENSIS:
t = ScanNestedCommand (TPAREN, CHAR_CLOSE_PARATHENSIS);
break;
case CHAR_OPEN_BRACES:
t = ScanNestedCommand (TBRACE, CHAR_CLOSE_BRACES);
break;
/*
* Format for: select word in list do .... done
* select word do .... done
* for word in list do .... done
* for word do .... done
*/
case PARSE_FOR:
case PARSE_SELECT:
t = (C_Op *)CreateTreeNode (sizeof (C_Op));
t->type = (c == PARSE_FOR) ? TFOR : TSELECT;
CheckNextSymbolIS (PARSE_WORD, FALSE);
AtStartOfList = TRUE;
t->str = CurrentParseObject.String;
AllowMultipleLines++;
t->words = GetINWordList (); /* Check for in etc */
/* CHeck for "for/select word in word...; do" versus "for/select word do" */
c = GetNextSymbol (FALSE);
if ((t->words == (char **)NULL) && (c != CHAR_NEW_LINE))
PeekSymbol = c;
else if ((t->words != (char **)NULL) && (c != CHAR_NEW_LINE) &&
(c != ';'))
ParseError (SyntaxErrorMessage);
t->left = GetDoDoneCommandList (FALSE);
AllowMultipleLines--;
break;
/*
* Format for: function name { .... }
*/
case PARSE_FUNCTION:
t = (C_Op *)CreateTreeNode (sizeof (C_Op));
t->type = TFUNC;
CheckNextSymbolIS (PARSE_WORD, FALSE);
t->str = CurrentParseObject.String;
AtStartOfList = TRUE;
AllowMultipleLines++;
CheckNextSymbolIS (CHAR_OPEN_BRACES, FALSE);
t->left = ScanNestedCommand (TBRACE, CHAR_CLOSE_BRACES);
AllowFunctions = FALSE;
AllowMultipleLines--;
CheckNextSymbolIS (CHAR_NEW_LINE, FALSE);
PeekSymbol = CHAR_NEW_LINE;
break;
/*
* Format for: while command do ... done
* until command do ... done
*/
case PARSE_WHILE:
case PARSE_UNTIL:
AllowMultipleLines++;
t = (C_Op *)CreateTreeNode (sizeof (C_Op));
t->type = (c == PARSE_WHILE) ? TWHILE : TUNTIL;
t->left = CommandList (TRUE);
t->right = GetDoDoneCommandList (TRUE);
t->words = (char **)NULL;
AllowMultipleLines--;
break;
/*
* Format for: case name in .... esac
*/
case PARSE_CASE:
(t = (C_Op *)CreateTreeNode (sizeof (C_Op)))->type = TCASE;
CheckNextSymbolIS (PARSE_WORD, FALSE);
t->str = CurrentParseObject.String;
AtStartOfList = TRUE;
AllowMultipleLines++;
CheckNextSymbolIS (PARSE_IN, TRUE);
AtStartOfList = TRUE;
t->left = CaseList();
CheckNextSymbolIS (PARSE_ESAC, FALSE);
AllowMultipleLines--;
break;
/*
* Format for: if command then command fi
* if command then command else command fi
* if command then command elif command then ... else ... fi
*/
case PARSE_IF:
AllowMultipleLines++;
(t = (C_Op *)CreateTreeNode (sizeof (C_Op)))->type = TIF;
t->left = CommandList (FALSE);
t->right = ThenPartList ();
CheckNextSymbolIS (PARSE_FI, FALSE);
AllowMultipleLines--;
break;
}
while (SynchroniseIOList (FALSE))
;
/* Add Word List and IO Actions to Tree Node. First process the IO Actions */
if (IOActionBlock)
{
t->ioact = (IO_Actions **)GetWordList (AddWordToBlock (NOWORD,
IOActionBlock));
IOActionBlock = (Word_B *)NULL;
}
else
t->ioact = (IO_Actions **)NULL;
if (t->type != TCOM)
{
if ((t->type != TPAREN) && (t->ioact != (IO_Actions **)NULL))
{
t = InitialiseTreeNode (TPAREN, t, NOBLOCK, NOWORDS);
t->ioact = t->left->ioact;
t->left->ioact = (IO_Actions **)NULL;
}
}
/* Terminate Word List */
else
{
WordListBlock = AddWordToBlock (NOWORD, WordListBlock);
t->words = CopyWordList ();
}
/* Restore IO list on exit */
IOActionBlock = iosave;
return t;
}
/*
* Processing for the do grouping - do ... done
*/
static C_Op * near GetDoDoneCommandList (bool onlydone)
{
register int c;
register C_Op *list;
if (((c = GetNextSymbol (TRUE)) == PARSE_DONE) && onlydone)
return (C_Op *)NULL;
if (c != PARSE_DO)
ParseError (SyntaxErrorMessage);
list = CommandList (FALSE);
CheckNextSymbolIS (PARSE_DONE, FALSE);
return list;
}
/*
* Handle the then part of an if statement
*/
static C_Op * near ThenPartList (void)
{
register int c;
register C_Op *t;
if ((c = GetNextSymbol (FALSE)) != PARSE_THEN)
{
PeekSymbol = c;
return (C_Op *)NULL;
}
(t = (C_Op *)CreateTreeNode (sizeof (C_Op)))->type = 0;
if ((t->left = CommandList (TRUE)) == (C_Op *)NULL)
ParseError (SyntaxErrorMessage);
t->right = ElsePartList ();
return t;
}
/*
* Handle the else part of an if statement
*/
static C_Op * near ElsePartList (void)
{
register int c;
register C_Op *t;
switch (c = GetNextSymbol (FALSE))
{
case PARSE_ELSE:
if ((t = CommandList (TRUE)) == (C_Op *)NULL)
ParseError (SyntaxErrorMessage);
return t;
case PARSE_ELIF:
(t = (C_Op *)CreateTreeNode (sizeof (C_Op)))->type = TELIF;
t->left = CommandList (FALSE);
t->right = ThenPartList ();
return t;
default:
PeekSymbol = c;
return (C_Op *)NULL;
}
}
/*
* Process the CASE statment
*/
static C_Op * near CaseList (void)
{
register C_Op *t = (C_Op *)NULL;
while ((PeekSymbol = GetNextSymbol (TRUE)) != PARSE_ESAC)
t = GenerateListNode (t, CaseListEntries ());
return t;
}
/*
* Process an individual case entry: pattern) commands;;
*/
static C_Op * near CaseListEntries (void)
{
register C_Op *t = (C_Op *)CreateTreeNode (sizeof (C_Op));
t->type = TPAT;
t->words = GetCasePatterns ();
CheckNextSymbolIS (CHAR_CLOSE_PARATHENSIS, FALSE);
t->left = CommandList (TRUE);
if ((PeekSymbol = GetNextSymbol (TRUE)) != PARSE_ESAC)
CheckNextSymbolIS (PARSE_BREAK, TRUE);
return t;
}
/*
* Get the case pattern - pattern | pattern
*/
static char ** near GetCasePatterns (void)
{
register int c;
register bool IgnoreNewLines;
IgnoreNewLines = TRUE;
/* Get each word which is separated by a | */
do
{
CheckNextSymbolIS (PARSE_WORD, IgnoreNewLines);
WordListBlock = AddWordToBlock (CurrentParseObject.String,
WordListBlock);
IgnoreNewLines = FALSE;
} while ((c = GetNextSymbol (FALSE)) == '|');
/* Save the patterns */
PeekSymbol = c;
WordListBlock = AddWordToBlock (NOWORD, WordListBlock);
return CopyWordList ();
}
/* Handle the in words.... part of a for or select statement. Get the
* words and build a list.
*/
static char ** near GetINWordList (void)
{
register int c;
/* Check to see if the next symbol is "in". If not there are no words
* following
*/
if ((c = GetNextSymbol (FALSE)) != PARSE_IN)
{
PeekSymbol = c;
return (char **)NULL;
}
/* Yes - get the WORDs following to the next non-word symbol */
AtStartOfList = FALSE;
while ((c = GetNextSymbol (FALSE)) == PARSE_WORD)
WordListBlock = AddWordToBlock (CurrentParseObject.String,
WordListBlock);
/* Check we got something */
if ((WordListBlock == (Word_B *)NULL) || !WordListBlock->w_nword)
ParseError (SyntaxErrorMessage);
/* Terminate the list */
WordListBlock = AddWordToBlock (NOWORD, WordListBlock);
PeekSymbol = c;
return CopyWordList ();
}
/*
* supporting functions
*/
static C_Op * near GenerateListNode (register C_Op *t1, register C_Op *t2)
{
if (t1 == (C_Op *)NULL)
return t2;
if (t2 == (C_Op *)NULL)
return t1;
return InitialiseTreeNode (TLIST, t1, t2, NOWORDS);
}
static C_Op * near InitialiseTreeNode (int type, C_Op *t1, C_Op *t2, char **wp)
{
register C_Op *t = (C_Op *)CreateTreeNode (sizeof (C_Op));
t->type = type;
t->left = t1;
t->right = t2;
t->words = wp;
return t;
}
static struct res {
char *r_name;
int r_val;
} restab[] = {
{ "for", PARSE_FOR}, {"case", PARSE_CASE},
{ "esac", PARSE_ESAC}, {"while", PARSE_WHILE},
{ "do", PARSE_DO}, {"done", PARSE_DONE},
{ "if", PARSE_IF}, {"in", PARSE_IN},
{ "then", PARSE_THEN}, {"else", PARSE_ELSE},
{ "elif", PARSE_ELIF}, {"until", PARSE_UNTIL},
{ "fi", PARSE_FI}, {"select", PARSE_SELECT},
{ "||", PARSE_LOGICAL_OR}, {";;", PARSE_BREAK},
{ "&&", PARSE_LOGICAL_AND}, {"{", CHAR_OPEN_BRACES},
{ "}", CHAR_CLOSE_BRACES}, {"function", PARSE_FUNCTION},
{ "((", PARSE_EXPRESSION}, { "[[", PARSE_TEST},
{ (char *)NULL, 0}
};
int LookUpSymbol (register char *n)
{
register struct res *rp = restab;
while ((rp->r_name != (char *)NULL) && strcmp (rp->r_name, n))
rp++;
return rp->r_val;
}
static char ** near CopyWordList (void)
{
register char **wd = GetWordList (WordListBlock);
WordListBlock = (Word_B *)NULL;
return wd;
}
static IO_Actions * near AddIOAction (int u, int f, char *cp)
{
IO_Actions *iop = (IO_Actions *)CreateTreeNode (sizeof (IO_Actions));
iop->io_unit = u;
iop->io_flag = f;
iop->io_name = cp;
IOActionBlock = AddWordToBlock ((char *)iop, IOActionBlock);
return iop;
}
static void near ParseError (char *s)
{
ParseErrorDectected = TRUE;
if (Interactive ())
{
AllowMultipleLines = 0;
while ((!CheckForEndOfFile ()) &&
(GetNextSymbol (FALSE) != CHAR_NEW_LINE))
continue;
}
ShellErrorMessage (s);
TerminateCurrentEnvironment ();
}
static int near GetNextSymbol (bool IgnoreNewLines)
{
register int c, c1;
int Type;
bool atstart;
if ((c = PeekSymbol) > 0)
{
PeekSymbol = 0;
if (c == CHAR_NEW_LINE)
AtStartOfList = TRUE;
return c;
}
e.linep = e.cline;
atstart = AtStartOfList;
AtStartOfList = FALSE;
CurrentParseObject.Integer = 0;
loop:
while ((c = GetNextCharacter (0)) == CHAR_SPACE || c == CHAR_TAB)
;
switch (c)
{
default:
if (isdigit (c))
{
ReturnGotCharacter (c1 = GetNextCharacter (0));
if ((c1 == '<') || (c1 == '>'))
{
CurrentIOUnit = c - '0';
goto loop;
}
*e.linep++ = (char)c;
c = c1;
}
break;
case '#':
while ((c = GetNextCharacter (0)) != 0 && (c != CHAR_NEW_LINE))
continue;
ReturnGotCharacter (c);
goto loop;
case 0:
return c;
/* Allow $name, ${name}, $(command) and support $((arthmetic functions)) */
case '$':
*e.linep++ = (char)c;
/* Handle $(..) and $((...)) */
if ((c = GetNextCharacter (0)) == CHAR_OPEN_PARATHENSIS)
{
*e.linep++ = (char)c;
if ((c = GetNextCharacter (0)) != CHAR_OPEN_PARATHENSIS)
Type = SWT_STDOUT;
else
Type = SWT_EXPRESSION;
if (ScanForEndofWord (c, Type))
return 0;
goto pack;
}
/* Handle ${...} */
else if (c == CHAR_OPEN_BRACES)
{
if (ScanForEndofWord (c, SWT_EVARIABLE))
return 0;
goto pack;
}
break;
case CHAR_BACKQUOTE:
case CHAR_SINGLE_QUOTE:
case CHAR_DOUBLE_QUOTE:
if ((c = CollectInputToCharacter (c, c)))
return c;
goto pack;
case '|':
case '&':
case ';':
case CHAR_OPEN_PARATHENSIS:
if ((c1 = CheckForDoubleCharacterCommands (c)))
{
AliasContinuationAllowed = FALSE;
AtStartOfList = TRUE;
return c1;
}
case CHAR_CLOSE_PARATHENSIS:
AliasContinuationAllowed = FALSE;
AtStartOfList = TRUE;
return c;
case CHAR_NOT:
AliasContinuationAllowed = FALSE;
AtStartOfList = TRUE;
return '|';
case '>':
case '<':
AliasContinuationAllowed = FALSE;
GetCurrentIOAction (c);
return c;
case CHAR_NEW_LINE:
GetAllHereFiles ();
AtStartOfList = TRUE;
if (((AllowMultipleLines || IgnoreNewLines)) && IgnoreNewLines)
goto loop;
return c;
}
ReturnGotCharacter (c);
pack:
while (((c = GetNextCharacter (0)) != 0) &&
(!any ((char)c, "`$ '\"\t;&<>()|^\n")))
{
if (e.linep >= e.eline)
ShellErrorMessage ("word too long");
else
*e.linep++ = (char)c;
}
ReturnGotCharacter (c);
if (any ((char)c, spcl2))
goto loop;
*e.linep++ = '\0';
if (atstart && (c = LookUpSymbol (e.cline)) != 0)
{
AliasContinuationAllowed = FALSE;
AtStartOfList = TRUE;
return c;
}
/* Otherwise, handle words beginning with a ~ */
if (*e.cline == '~')
{
char *dir;
int off = 2;
/* OLDPWD or PWD if - or + */
if (*(e.cline + 1) == '+')
dir = GetVariableAsString (PWDVariable, FALSE);
else if (*(e.cline + 1) == '-')
dir = GetVariableAsString (OldPWDVariable, FALSE);
/* No - use home directory */
else
{
dir = GetVariableAsString (HomeVariableName, FALSE);
off = 1;
}
CurrentParseObject.String = CreateTreeNode (strlen (e.cline) +
strlen (dir));
strcat (strcpy (CurrentParseObject.String, dir), e.cline + off);
}
/* Otherwise, just save it */
else
CurrentParseObject.String = StringCopy (e.cline);
return PARSE_WORD;
}
/* Read input until we read the specified end character */
int CollectInputToCharacter (register int c, register int EndCharacter)
{
*(e.linep++) = (char)c; /* Save the current character */
/* Check for end - matching character */
while ((c = GetNextCharacter (EndCharacter)) != EndCharacter)
{
/* End of file - abort */
if (c == 0)
return MC_Error (0, EndCharacter, MissingEndMessage);
if (c == '\\')
{
*(e.linep++) = (char)c;
if ((c = GetNextCharacter (EndCharacter)) == 0)
return MC_Error (0, EndCharacter, MissingEndMessage);
}
*(e.linep++) = (char)c;
}
*(e.linep++) = (char)c;
return 0;
}
/* Check for &&, || and ;; */
static int near CheckForDoubleCharacterCommands (register int c)
{
char s[3];
register char *cp = s;
/* Get the next character and set up double string. Look up in valid
* operators. If invalid, unget character
*/
*cp++ = (char)c;
*cp++ = (char)GetNextCharacter (0);
*cp = 0;
if ((c = LookUpSymbol (s)) == 0)
ReturnGotCharacter (*--cp);
return c;
}
/* Process I/O re-direction */
static void near GetCurrentIOAction (register int ec)
{
register int c;
/* Get the next character to see if it is a re-direction character as well */
if (((c = GetNextCharacter (0)) == '>') || (c == '<'))
{
/* Check for open in read/write mode */
if ((ec == '<') && (c == '>'))
CurrentParseObject.Integer = IOWRITE | IOREAD;
/* Otherwise, we must have a double character */
else if (c != ec)
ParseError (SyntaxErrorMessage);
else
CurrentParseObject.Integer = (ec == '>') ? IOWRITE | IOCAT : IOHERE;
c = GetNextCharacter (0);
}
else
CurrentParseObject.Integer = (ec == '>') ? IOWRITE : IOREAD;
/* Check for >|, >&, <& and <<- */
if ((c == '-') && (CurrentParseObject.Integer == IOHERE))
CurrentParseObject.Integer |= IOTHERE;
else if ((c == '|') && (CurrentParseObject.Integer == IOWRITE))
CurrentParseObject.Integer |= IOCLOBBER;
else if ((c != '&') || (CurrentParseObject.Integer == IOHERE))
ReturnGotCharacter (c);
else
CurrentParseObject.Integer |= IODUP;
}
/* Get a new tree leaf structure */
static char * near CreateTreeNode (size_t size)
{
register char *t;
if ((t = AllocateMemoryCell (size)) == (char *)NULL)
{
ShellErrorMessage ("command line too complicated");
TerminateCurrentEnvironment ();
}
return t;
}
/*
* Produce the characters from an alias.
*/
static int Alias_GetNextCharacter (IO_State *iop)
{
register int c;
if (iop->argp->aword == (char *)NULL)
c = 0;
else
c = *(iop->argp->aword++);
/* Check for end of alias */
if (!c)
InAlias = FALSE;
/* Check for continuation allowed */
if ((c == CHAR_SPACE) && !*(iop->argp->aword))
AliasContinuationAllowed = TRUE;
return c;
}
/*
* Handler the finding of a word object
*/
static bool near ProcessWordObject (C_Op **t, bool FoundAlias)
{
AliasList *al;
char *val = CurrentParseObject.String;
PeekSymbol = 0;
if (*t == (C_Op *)NULL)
{
if (!InAlias && !FoundAlias &&
((al = LookUpAlias (val, TRUE)) != (AliasList *)NULL))
{
InAlias = TRUE;
PUSHIO (aword, al->value, Alias_GetNextCharacter, null);
return FALSE;
}
/* No - generate a new node for it */
(*t = (C_Op *)CreateTreeNode (sizeof (C_Op)))->type = TCOM;
}
/* Check for AliasContinuation - a space at the end of the alias */
else if (AliasContinuationAllowed && !InAlias &&
((al = LookUpAlias (val, TRUE)) != (AliasList *)NULL))
{
AliasContinuationAllowed = FALSE;
InAlias = TRUE;
PUSHIO (aword, al->value, Alias_GetNextCharacter, null);
return FALSE;
}
WordListBlock = AddWordToBlock (val, WordListBlock);
return TRUE;
}
/*
* Missing end character
*/
static int near MC_Error (int end, int EndCharacter, char *message)
{
ReturnGotCharacter (end);
message[strlen (message) - 1] = (char)EndCharacter;
ParseError (message);
return YYERRCODE;
}
/*
* Handle the ((....)) case
*/
static C_Op * near ParseExpression (int Type, char *Command)
{
C_Op *t;
char *Start = e.cline;
(t = (C_Op *)CreateTreeNode (sizeof (C_Op)))->type = TCOM;
/* Initialise the input line */
e.linep = e.cline;
/* Collect up to terminating double */
if (ScanForEndofWord ((Type == SWT_CONDITIONAL) ? CHAR_SPACE
: CHAR_DOUBLE_QUOTE, Type))
return t;
/* Put the string inside double quotes to stop interpretation */
if (Type == SWT_CONDITIONAL)
{
*(e.linep - 2) = 0;
++Start;
}
else
{
*(e.linep - 2) = CHAR_DOUBLE_QUOTE;
*(e.linep - 1) = 0;
}
/* Save the command as let and the string itself */
WordListBlock = AddWordToBlock (StringCopy (Command), WordListBlock);
WordListBlock = AddWordToBlock (StringCopy (Start), WordListBlock);
return t;
}
/*
* Scan for end of either $(...), ${...}, ((....)), [[....]], $((...))
*
* Return 0 at end of string.
*/
static struct SWT_table {
char Start;
char End;
bool Double;
} SWT_Table [] =
{
{ CHAR_OPEN_PARATHENSIS, CHAR_CLOSE_PARATHENSIS, FALSE },
{ CHAR_OPEN_BRACES, CHAR_CLOSE_BRACES, FALSE },
{ CHAR_OPEN_PARATHENSIS, CHAR_CLOSE_PARATHENSIS, TRUE },
{ CHAR_OPEN_BRACKETS, CHAR_CLOSE_BRACKETS, TRUE },
{ CHAR_OPEN_PARATHENSIS, CHAR_CLOSE_PARATHENSIS, TRUE },
};
int ScanForEndofWord (int Current, int Type)
{
struct SWT_table *SWTp = &SWT_Table[Type];
int Rchar;
int NewType;
bool FirstTime = FALSE;
/* Handle some funny cases: () for example */
if (Current == SWTp->End)
FirstTime = TRUE;
else
*(e.linep)++ = (char)Current; /* Save the current character */
while (TRUE)
{
/* Get the next character and check for end of string */
if (FirstTime ||
((Current = GetNextCharacter (SWTp->End)) == SWTp->End))
{
FirstTime = FALSE;
*(e.linep++) = (char)Current;
/* If this is a double, we need both */
if (!SWTp->Double)
return 0;
if ((Current = GetNextCharacter (SWTp->End)) == SWTp->End)
{
*(e.linep++) = (char)Current;
return 0;
}
}
if ((Current == CHAR_SINGLE_QUOTE) || (Current == CHAR_DOUBLE_QUOTE))
{
if ((Type = CollectInputToCharacter (Current, Current)))
return Type;
continue;
}
/* Special Processing is required for these */
else if ((Current == '$') || (Current == CHAR_OPEN_PARATHENSIS) ||
(Current == CHAR_OPEN_BRACKETS))
{
*(e.linep++) = (char)Current;
Rchar = Current;
NewType = -1;
/* Get the next character */
if ((Current = GetNextCharacter (0)) == 0)
return MC_Error (0, SWTp->End, MissingEndMessage);
if (Rchar == '$')
{
if (Current == CHAR_OPEN_PARATHENSIS)
{
*(e.linep++) = (char)Current;
if ((Current = GetNextCharacter (0)) == 0)
return MC_Error (0, SWTp->End, MissingEndMessage);
NewType = (Current == CHAR_OPEN_PARATHENSIS)
? SWT_EXPRESSION : SWT_STDOUT;
}
else if (Current == CHAR_OPEN_BRACES)
NewType = SWT_EVARIABLE;
}
else if ((Rchar == CHAR_OPEN_PARATHENSIS) &&
(Current == CHAR_OPEN_PARATHENSIS))
NewType = SWT_LET;
else if ((Rchar == CHAR_OPEN_BRACKETS) &&
(Current == CHAR_OPEN_BRACKETS))
NewType = SWT_CONDITIONAL;
if (NewType != -1)
{
if ((Type = ScanForEndofWord (Current, NewType)))
return Type;
continue;
}
}
else if (Current == '\\')
{
*(e.linep++) = (char)Current;
Current = GetNextCharacter (0);
}
/* Check for End of file - abort */
if (Current == 0)
return MC_Error (0, SWTp->End, MissingEndMessage);
*(e.linep++) = (char)Current;
}
}